<?php

namespace hangpu8\hpcms;

use hangpu8\hpcms\Utils\Json;
use PDO;

class Install
{
    private $rootPath;
    private $hpcmsRoot;

    /**
     * 构造函数
     */
    public function __construct()
    {
        // 获得路径
        $this->hpcmsRoot = str_replace('\\', '/', __DIR__);
        $this->rootPath = str_replace('\\', '/', dirname(dirname(dirname(dirname(__DIR__)))));
    }
    // 初始化安装程序
    public function run($boot)
    {
        // 判断是否复制文件，不存在跳转安装页面
        $server = request()->server();
        $urlPath = isset($server['REQUEST_URI']) ? $server['REQUEST_URI'] : '';
        if (empty($urlPath))
        {
            return;
        }
        $installArr = [
            '/install/step1',
            '/install/step2',
            '/install/step3',
            '/install/step4',
            '/install/step5',
            '/install/step1.html',
            '/install/step2.html',
            '/install/step3.html',
            '/install/step4.html',
            '/install/step5.html',
        ];
        $installFilePath = "{$this->rootPath}/public/install/step1.html";
        if (file_exists($installFilePath) && !in_array($urlPath, $installArr)) {
            header("location:/install/step1.html");
            exit;
        } else if (!file_exists($installFilePath)) {
            $installFilePath = dirname($installFilePath);
            $installPath = "{$this->hpcmsRoot}/tpl/install/";
            copy_to_file($installPath,"{$installFilePath}/");
            header("location:/install/step1.html");
            exit;
        }
    }

    // 安装程序，第一步（使用协议）
    public function step1()
    {
        $agreement = file_get_contents("{$this->rootPath}/public/install/static/agreement.txt");
        return Json::successful(['content' => $agreement]);
    }

    // 安装程序，第二步（环境检测）
    public function step2()
    {
        $server = $this->getServer();
        $fun = $this->checkFun();
        $dirAuth = $this->dirAuth();
        $data = [
            'server'                => $server,
            'fun'                   => $fun,
            'dir'                   => $dirAuth
        ];
        return Json::successful($data);
    }

    /**
     * 检测函数是否启用
     *
     * @return void
     */
    private function checkFun()
    {
        $data = [
            [
                'name'              => 'GD库',
                'result'            => get_extension_funcs("gd") ? true : false,
                'value'             => get_extension_funcs("gd") ? '已开启' : '未开启',
            ],
        ];
        return $data;
    }

    /**
     * 检测目录权限
     *
     * @return void
     */
    private function dirAuth()
    {
        $dirAuth = [
            [
                'path'              => "{$this->rootPath}/public",
                'name'              => "{$this->rootPath}/public",
            ],
            [
                'path'              => "{$this->rootPath}/runtime",
                'name'              => "{$this->rootPath}/runtime",
            ],
            [
                'path'              => "{$this->rootPath}/vendor",
                'name'              => "{$this->rootPath}/vendor",
            ],
        ];
        $data = [];
        foreach ($dirAuth as $key => $value) {
            $data[$key]['name'] = $value['name'];
            $data[$key]['result'] = is_writable($value['path']) ? true : false;
            $data[$key]['value'] = is_writable($value['path']) ? '可写入' : '不可写入';
        }
        return $data;
    }

    /**
     * 获得服务器信息
     *
     * @return void
     */
    private function getServer()
    {
        $server = request()->server();
        $data = [
            [
                'name'              => '应用域名',
                'result'            => true,
                'value'             => "{$server['REQUEST_SCHEME']}://{$server['HTTP_HOST']}",
            ],
            [
                'name'              => '操作系统',
                'result'            => true,
                'value'             => PHP_OS,
            ],
            [
                'name'              => '编译引擎',
                'result'            => true,
                'value'             => $server['SERVER_SOFTWARE'],
            ],
            [
                'name'              => 'PHP版本',
                'result'            => !version_compare(PHP_VERSION, '7.2.5', '<'),
                'value'             => PHP_VERSION . "（推荐7.3，最低7.2.5）",
            ],
            [
                'name'              => '安装目录',
                'result'            => true,
                'value'             => $this->rootPath,
            ],
        ];
        return $data;
    }

    // 安装程序：第三步（GET获取数据，POST检测数据配置）
    public function step3()
    {
        if (request()->isPost()) {
            $post = request()->post();
            $type = isset($post['database'][0]['value']) ? $post['database'][0]['value'] : '';
            $host = isset($post['database'][1]['value']) ? $post['database'][1]['value'] : '';
            $database = isset($post['database'][4]['value']) ? trim($post['database'][4]['value']) : '';
            $port = isset($post['database'][2]['value']) ? $post['database'][2]['value'] : '';
            $user = isset($post['database'][3]['value']) ? trim($post['database'][3]['value']) : '';
            $password = isset($post['database'][2]['value']) ? trim($post['database'][5]['value']) : '';
            $prefix = isset($post['database'][7]['value']) ? trim($post['database'][7]['value']) : '';
            try {
                // 数据库连接检测
                $dsn = "{$type}:dbname={$database};host={$host};port={$port}";
                $pdo = new PDO($dsn, $user, $password);
            } catch (\PDOEXception $e) {
                return Json::fail($e->getMessage());
            }
            // 检测表是否为空
            $result = $pdo->query("SHOW TABLES LIKE '{$prefix}admin'");
            $row = $result->fetchAll();
            if (count($row) == 1) {
                return Json::fail('该数据库表已存在或已安装');
            }
            return Json::successful([]);
        } else {
            $data = [
                'mysqlType'             => $this->getMysqlType(),
                'mysqlList'             => $this->getMysqlConfig(),
                'admin'                 => $this->getAdminConfig(),
            ];
            return Json::successful($data);
        }
    }

    /**
     * 管理员配置
     *
     * @return void
     */
    private function getAdminConfig()
    {
        $data = [
            [
                'field'             => 'username',
                'type'              => 'text',
                'name'              => '登录账号',
                'value'             => '',
                'tip'               => '后台系统管理员账号，不允许删除',
            ],
            [
                'field'             => 'password',
                'type'              => 'password',
                'name'              => '登录密码',
                'value'             => '',
                'tip'               => '系统管理员登录密码',
            ],
            [
                'field'             => 'password',
                'type'              => 'password',
                'name'              => '重复密码',
                'value'             => '',
                'tip'               => '请在一次输入登录密码',
            ],
        ];
        return $data;
    }

    /**
     * 获取数据库配置参数
     *
     * @return void
     */
    private function getMysqlConfig()
    {
        $data = [
            [
                'field'             => 'type',
                'name'              => '数据库类型',
                'value'             => 'mysql',
            ],
            [
                'field'             => 'host',
                'name'              => '数据库地址',
                'value'             => '127.0.0.1',
            ],
            [
                'field'             => 'port',
                'name'              => '数据库端口',
                'value'             => '3306',
            ],
            [
                'field'             => 'user',
                'name'              => '数据库用户',
                'value'             => '',
            ],
            [
                'field'             => 'database',
                'name'              => '数据库名称',
                'value'             => '',
            ],
            [
                'field'             => 'password',
                'name'              => '数据库密码',
                'value'             => '',
            ],
            [
                'field'             => 'charset',
                'name'              => '数据库字符',
                'value'             => 'utf8',
            ],
            [
                'field'             => 'prefix',
                'name'              => '数据表前缀',
                'value'             => 'php_',
            ],
        ];
        return $data;
    }

    /**
     * 获取数据库类型
     *
     * @return void
     */
    private function getMysqlType()
    {
        $data = [
            [
                'name'              => 'mysql',
                'value'             => 'mysql',
            ],
        ];
        return $data;
    }

    /**
     * 开始安装数据
     *
     * @return void
     */
    public function step4()
    {
        $act = request()->post('act');
        $post = request()->post('data');
        switch ($act) {
            case 'database':
                $sqlPath = "{$this->rootPath}/public/install/data/data.sql";
                if (!file_exists($sqlPath)) {
                    return Json::fail('找不到数据表结构文件');
                }
                // 获取参数
                $type = isset($post[0]['value']) ? $post[0]['value'] : '';
                $host = isset($post[1]['value']) ? $post[1]['value'] : '';
                $database = isset($post[4]['value']) ? trim($post[4]['value']) : '';
                $port = isset($post[2]['value']) ? $post[2]['value'] : '';
                $user = isset($post[3]['value']) ? trim($post[3]['value']) : '';
                $password = isset($post[5]['value']) ? trim($post[5]['value']) : '';
                $prefix = isset($post[7]['value']) ? trim($post[7]['value']) : '';

                // 读取模板SQL
                $_sql = file_get_contents($sqlPath);
                $_sql = str_replace("php_", $prefix, $_sql);
                $_arr = explode(';', $_sql);
                $_arr = array_filter($_arr);
                try {
                    // 数据库连接检测
                    $dsn = "{$type}:dbname={$database};host={$host};port={$port}";
                    $pdo = new PDO($dsn, $user, $password);
                } catch (\PDOEXception $e) {
                    return Json::fail($e->getMessage());
                }
                try {
                    // 执行SQL
                    foreach ($_arr as $value) {
                        $pdo->query("{$value};");
                    }
                } catch (\Throwable $e) {
                    return Json::fail($e->getMessage());
                }
                $data = [
                    '数据表创建成功...',
                    '导入数据成功...',
                ];
                return Json::successful($data, '数据库操作完成');
                break;
            case 'admin':
                $databasePost = $post['database'];
                $adminPost = $post['admin'];
                // 数据库获取参数
                $type = isset($databasePost[0]['value']) ? $databasePost[0]['value'] : '';
                $host = isset($databasePost[1]['value']) ? $databasePost[1]['value'] : '';
                $database = isset($databasePost[4]['value']) ? trim($databasePost[4]['value']) : '';
                $port = isset($databasePost[2]['value']) ? $databasePost[2]['value'] : '';
                $user = isset($databasePost[3]['value']) ? trim($databasePost[3]['value']) : '';
                $password = isset($databasePost[5]['value']) ? trim($databasePost[5]['value']) : '';
                $prefix = isset($databasePost[7]['value']) ? trim($databasePost[7]['value']) : '';
                // 获取管理员参数
                $username = isset($adminPost[0]['value']) ? $adminPost[0]['value'] : '';
                $userPwd = isset($adminPost[1]['value']) ? md5($adminPost[1]['value']) : '';
                try {
                    // 数据库连接检测
                    $dsn = "{$type}:dbname={$database};host={$host};port={$port}";
                    $pdo = new PDO($dsn, $user, $password);
                    $date = date("Y-m-d H:i:s");
                    $sql = "INSERT INTO `{$prefix}admin` VALUES (1,'{$date}','{$date}',1,'{$username}','{$userPwd}',1,'超级管理员','0',NULL,NULL,'');";
                    $pdo->query($sql);
                } catch (\PDOEXception $e) {
                    return Json::fail($e->getMessage());
                }
                $data = [
                    '管理员创建完成...',
                ];
                return Json::successful($data, '管理员操作完成');
                break;
            case 'background':
                try {
                    $databasePost = $post['database'];
                    $adminPost = $post['admin'];
                    // 数据库获取参数
                    $type = isset($databasePost[0]['value']) ? $databasePost[0]['value'] : '';
                    $host = isset($databasePost[1]['value']) ? $databasePost[1]['value'] : '';
                    $database = isset($databasePost[4]['value']) ? trim($databasePost[4]['value']) : '';
                    $port = isset($databasePost[2]['value']) ? $databasePost[2]['value'] : '';
                    $user = isset($databasePost[3]['value']) ? trim($databasePost[3]['value']) : '';
                    $password = isset($databasePost[5]['value']) ? trim($databasePost[5]['value']) : '';
                    $charset = isset($databasePost[6]['value']) ? trim($databasePost[6]['value']) : '';
                    $prefix = isset($databasePost[7]['value']) ? trim($databasePost[7]['value']) : '';
                    // 拼接配置文件路径
                    $currentEnvPath = "{$this->rootPath}/public/install/data/env.tpl";
                    $envPath = "{$this->rootPath}/.env";
                    // 读取配置文件
                    $envConfig = file_get_contents($currentEnvPath);
                    // 替换配置文件参数
                    $str1 = ["{type}", "{host}", "{database}", "{username}", "{password}", "{port}", "{charset}", "{prefix}"];
                    $str2 = [$type, $host, $database, $user, $password, $port, $charset, $prefix];
                    $envConfig = str_replace($str1, $str2, $envConfig);
                    // 写入配置文件
                    file_put_contents($envPath, $envConfig);

                    // 复制后台静态文件
                    $newPath = "{$this->rootPath}/public/admin/";
                    if(!file_exists($newPath))
                    {
                        $oldPath = "{$this->hpcmsRoot}/tpl/admin/";
                        copy_to_file($oldPath,$newPath);
                    }
                    // 复制默认远程组件
                    $newRemotePath = "{$this->rootPath}/public/remote/";
                    if(!file_exists($newRemotePath))
                    {
                        $oldRemotePath = "{$this->hpcmsRoot}/tpl/remote/";
                        copy_to_file($oldRemotePath,$newRemotePath);
                    }
                    // 复制API文档静态文件
                    $apiNewPath = "{$this->rootPath}/public/apidoc/";
                    if (!file_exists($apiNewPath))
                    {
                        $apiOldPath = "{$this->hpcmsRoot}/tpl/apidoc/";
                        copy_to_file($apiOldPath,$apiNewPath);
                    }
                    $data = [
                        '静态文件安装完成...',
                    ];
                    return Json::successful($data, '后台目录操作完成');
                } catch (\Throwable $e) {
                    return Json::fail($e->getMessage());
                }
                break;
        }
    }

    /**
     * 删除文件确保安全
     *
     * @return void
     */
    public function step5()
    {
        // 跳转域名
        $server = request()->server();
        $domain  = "{$server['REQUEST_SCHEME']}://{$server['HTTP_HOST']}";
        $str = "恭喜您，安装完成！\n";
        $str .= "请手动删除public目录下的install文件夹\n";
        $data = [
            'content'           => $str,
            'adminUrl'          => "{$domain}/admin",
        ];
        return Json::successful($data);
    }
}
